/**
 * ============================================
 * Redis客户端配置模块
 *
 * 功能说明：
 * - 使用redis库提供Redis数据库连接和操作功能
 * - 存储验证码、会话令牌等临时数据
 * - 提供自动重连机制和连接状态监控
 * - 支持验证码和邮件验证码的存储、验证和删除
 *
 * 使用说明：
 * - 需要配置Redis服务器连接信息
 * - 调用storeCaptcha/storeEmailCode存储验证码
 * - 调用verifyCaptcha/verifyEmailCode验证验证码
 * - 系统会自动处理连接管理和错误恢复
 * ============================================
 */

// 引入redis库 - Node.js的Redis客户端库，支持现代Redis特性
const redis = require('redis');

/**
 * ====================
 * 创建Redis客户端
 * ====================
 * 功能：配置Redis服务器连接参数，创建客户端实例
 * 特性：支持自动重连、连接超时、密码认证等
 */
const client = redis.createClient({
  socket: {
    host: process.env.REDIS_HOST || '127.0.0.1',   // Redis服务器地址，默认本地
    port: process.env.REDIS_PORT || 6379,          // Redis端口，默认6379
    reconnectStrategy: (retries) => {
      // 重连策略：指数退避算法，避免频繁重连
      const delay = Math.min(retries * 100, 3000); // 最大延迟3秒
      console.log(`🔄 Redis重连尝试第${retries + 1}次，${delay}ms后重试...`);
      return delay;
    },
    connectTimeout: 10000, // 连接超时10秒
    lazyConnect: true,     // 延迟连接，避免应用启动时阻塞
  },
  password: process.env.REDIS_PASSWORD || null,    // Redis密码（如果有）
  database: process.env.REDIS_DB || 0,             // Redis数据库编号，默认0
});

/**
 * ====================
 * Redis事件处理
 * ====================
 * 功能：监听Redis客户端的各种状态事件
 * 提供详细的连接状态日志，便于监控和调试
 */

// 错误事件：处理连接和操作中的错误
client.on('error', (err) => {
  if (err.code === 'ECONNRESET') {
    console.warn('⚠️ Redis连接被重置，将自动重连...');
  } else {
    console.error('❌ Redis连接错误:', err);
  }
});

// 连接成功事件：客户端与Redis服务器建立连接
client.on('connect', () => {
  console.log('🔗 Redis连接成功');
});

// 准备就绪事件：客户端可以执行命令
client.on('ready', () => {
  console.log('✅ Redis准备就绪');
});

// 重连事件：客户端正在尝试重新连接
client.on('reconnecting', () => {
  console.log('🔄 Redis正在重新连接...');
});

// 连接关闭事件：客户端连接被关闭
client.on('end', () => {
  console.log('🔴 Redis连接已关闭');
});

// 连接断开事件：客户端与服务器断开连接
client.on('disconnect', () => {
  console.warn('⚠️ Redis连接断开');
});

/**
 * ====================
 * 连接Redis函数
 * ====================
 * 功能：建立Redis连接并处理连接失败的重试
 * 使用场景：应用启动时初始化Redis连接
 *
 * @returns {Promise<void>}
 */
const connectRedis = async () => {
  try {
    await client.connect();
    console.log('🚀 Redis客户端已启动');
  } catch (err) {
    console.error('❌ Redis初始连接失败:', err);
    // 初始连接失败时，5秒后自动重试
    setTimeout(connectRedis, 5000);
  }
};

/**
 * ====================
 * 启动Redis连接
 * ====================
 * 功能：应用启动时自动连接Redis
 * 确保Redis服务在需要时可用
 */
connectRedis();

/**
 * ====================
 * 定期连接状态检查
 * ====================
 * 功能：定期检查Redis连接状态，确保连接健康
 * 使用PING命令验证连接是否活跃
 */
setInterval(async () => {
  try {
    if (client.isOpen) {
      await client.ping(); // 发送PING命令检查连接
    }
  } catch (error) {
    console.warn('🔄 Redis连接状态检查失败，可能正在重连...');
  }
}, 30000); // 每30秒检查一次

/**
 * ====================
 * 验证码存储相关方法
 * ====================
 * 功能：提供图形验证码的存储、验证和删除功能
 * 使用Redis的setEx命令实现带过期时间的存储
 */

/**
 * 存储验证码到Redis
 * 功能：将图形验证码存储到Redis，设置过期时间
 * 安全性：验证码一次性使用，过期自动删除
 *
 * @param {string} captchaId - 验证码ID（通常是会话ID或唯一标识）
 * @param {string} captchaValue - 验证码值（用户需要识别的文本）
 * @param {number} expireTime - 过期时间（秒），默认300秒（5分钟）
 * @returns {Promise<boolean>} 存储是否成功
 */
const storeCaptcha = async (captchaId, captchaValue, expireTime = 300) => {
  try {
    // 使用setEx命令存储验证码，key格式：captcha:{captchaId}
    await client.setEx(`captcha:${captchaId}`, expireTime, captchaValue);
    return true;
  } catch (error) {
    console.error('存储验证码失败:', error);
    return false;
  }
};

/**
 * 验证验证码
 * 功能：验证用户输入的验证码是否正确
 * 特性：验证成功后自动删除验证码，确保一次性使用
 *
 * @param {string} captchaId - 验证码ID
 * @param {string} userInput - 用户输入的验证码
 * @returns {Promise<boolean>} 验证是否成功
 */
const verifyCaptcha = async (captchaId, userInput) => {
  try {
    // 从Redis获取存储的验证码
    const storedCaptcha = await client.get(`captcha:${captchaId}`);
    
    if (!storedCaptcha) {
      return false; // 验证码不存在或已过期
    }
    
    // 验证成功后删除验证码（一次性使用，防止重放攻击）
    await client.del(`captcha:${captchaId}`);
    
    // 不区分大小写比较（提高用户体验）
    return storedCaptcha.toLowerCase() === userInput.toLowerCase();
  } catch (error) {
    console.error('验证验证码失败:', error);
    return false;
  }
};

/**
 * 删除验证码
 * 功能：手动删除验证码，用于清理或取消验证
 *
 * @param {string} captchaId - 验证码ID
 * @returns {Promise<boolean>} 删除是否成功
 */
const deleteCaptcha = async (captchaId) => {
  try {
    await client.del(`captcha:${captchaId}`);
    return true;
  } catch (error) {
    console.error('删除验证码失败:', error);
    return false;
  }
};

/**
 * ====================
 * 邮件验证码相关方法
 * ====================
 * 功能：提供邮件验证码的存储、验证和删除功能
 * 与图形验证码类似，但针对邮件验证场景优化
 */

/**
 * 存储邮件验证码到Redis
 * 功能：将邮件验证码存储到Redis，设置较长的过期时间
 * 使用场景：用户注册、密码重置等需要邮件验证的场景
 *
 * @param {string} email - 邮箱地址（作为key的一部分）
 * @param {string} code - 验证码值
 * @param {number} expireTime - 过期时间（秒），默认600秒（10分钟）
 * @returns {Promise<boolean>} 存储是否成功
 */
const storeEmailCode = async (email, code, expireTime = 600) => {
  try {
    // 使用setEx命令存储邮件验证码，key格式：email_code:{email}
    await client.setEx(`email_code:${email}`, expireTime, code);
    return true;
  } catch (error) {
    console.error('存储邮件验证码失败:', error);
    return false;
  }
};

/**
 * 验证邮件验证码
 * 功能：验证用户输入的邮件验证码是否正确
 * 特性：验证成功后自动删除，确保安全性和一次性使用
 *
 * @param {string} email - 邮箱地址
 * @param {string} userInput - 用户输入的验证码
 * @returns {Promise<boolean>} 验证是否成功
 */
const verifyEmailCode = async (email, userInput) => {
  try {
    // 从Redis获取存储的邮件验证码
    const storedCode = await client.get(`email_code:${email}`);
    
    if (!storedCode) {
      return false; // 验证码不存在或已过期
    }
    
    // 验证成功后删除验证码（一次性使用）
    await client.del(`email_code:${email}`);
    
    // 不区分大小写比较
    return storedCode.toLowerCase() === userInput.toLowerCase();
  } catch (error) {
    console.error('验证邮件验证码失败:', error);
    return false;
  }
};

/**
 * 删除邮件验证码
 * 功能：手动删除邮件验证码，用于清理或取消操作
 *
 * @param {string} email - 邮箱地址
 * @returns {Promise<boolean>} 删除是否成功
 */
const deleteEmailCode = async (email) => {
  try {
    await client.del(`email_code:${email}`);
    return true;
  } catch (error) {
    console.error('删除邮件验证码失败:', error);
    return false;
  }
};

/**
 * ====================
 * 模块导出
 * ====================
 * 功能：导出Redis客户端和所有相关方法
 * 其他模块可以导入并使用这些功能
 */
module.exports = {
  client,            // Redis客户端实例，可用于执行其他Redis命令
  storeCaptcha,      // 存储图形验证码
  verifyCaptcha,     // 验证图形验证码
  deleteCaptcha,     // 删除图形验证码
  storeEmailCode,    // 存储邮件验证码
  verifyEmailCode,   // 验证邮件验证码
  deleteEmailCode,   // 删除邮件验证码
};